/*
 * data.c
 *
 *  Created on: Mar 12, 2013
 *      Author: abrahamsantini
 */
#include "data.h"
#include "stdio.h"
#include "stdlib.h"


int init_data(tdata_t *data, sharedMemory_t *sm) {
	producer_t *my_producer;
	my_producer = (producer_t* )malloc(sizeof(producer_t));
	init_producer (my_producer, sm);
	consumer_t *my_consumer;
	my_consumer = (consumer_t*)malloc(sizeof(consumer_t));
	init_consumer(my_consumer, sm);
	calculator_t *my_calc;
	my_calc = (calculator_t*) malloc(sizeof(calculator_t));
	init_calc(my_calc, sm);

	data->my_calc = my_calc;
	data->my_prod = my_producer;
	data->my_cons = my_consumer;
	data->my_io = 0;
	data->my_io_counter = 1;
	return 0;
}
//*************** CALCULATOR FUNCTIONS*************
int get_value(tdata_t *data) {
	//semaphore_t temp_sm;
	//temp_sm = data->my_calc->sm->calcMutex;
	int ret = semaphore_up(&data->my_calc->sm->calcMutex);
	if(ret>= 0){
		data->my_calc->my_value =data->my_calc->sm->calcValue;
	}
	return ret;
}

int square_value(tdata_t *data) {
	data->my_calc ->my_value *= data->my_calc ->my_value;
	return 1;
}

int mod_value(tdata_t *data) {
	data->my_calc ->my_value = data->my_calc -> my_value % 100;
	return 1;
}

int return_value(tdata_t *data) {
	data->my_calc->sm->calcValue = data->my_calc->my_value;
	return semaphore_down(&data->my_calc->sm->calcMutex);
}

int next_calc_instr(tdata_t *data) {
	int ret = 0;
	switch (data->my_calc->next_instr) {
	case 0:
		ret = get_value(data);
		break;

	case 1:
		ret = square_value(data);
		break;
	case 2:
		ret = mod_value(data);
		break;
	case 3:
		data->my_calc->num_of_cycles++;
		ret = return_value(data);
		break;
	case 4:
		break;
	case 5:
		break;
	case 6:
		break;
	case 7:
		break;
	case 8:
		break;
	case 9:
		break;
	case 10:
		break;
	case 11:
		break;
	case 12:
		break;
	case 13:
		break;
	case 14:
		break;
	case 15:
		break;
	case 16:
		break;
	case 17:
		break;
	case 18:
		break;
	case 19:
		break;
	case 20:
		break;
	case 21:
		break;
	case 22:
		break;
	case 23:
		break;
	case 24:
		break;
	case 25:
		break;
	case 26:
		break;
	case 27:
		break;
	case 28:
		break;
	case 29:
		break;
	case 30:
		break;
	case 31:
		break;
	case 32:
		break;
	case 33:
		break;
	case 34:
		break;
	case 35:
		break;
	case 36:
		break;
	case 37:
		break;
	case 38:
		break;
	case 39:
		break;
	case 40:
		break;
	case 41:
		break;
	case 42:
		break;
	case 43:
		break;
	case 44:
		break;
	case 45:
		break;
	case 46:
		break;
	case 47:
		break;
	case 48:
		break;
	case 49:
		break;
	case 50:
		break;
	case 51:
		break;
	case 52:
		break;
	case 53:
		break;
	case 54:
		break;
	case 55:
		break;
	case 56:
		break;
	case 57:
		break;
	case 58:
		break;
	case 59:
		break;
	case 60:
		break;
	case 61:
		break;
	case 62:
		break;
	case 63:
		break;
	case 64:
		break;
	case 65:
		break;
	case 66:
		break;
	case 67:
		break;
	case 68:
		break;
	case 69:
		break;
	case 70:
		break;
	case 71:
		break;
	case 72:
		break;
	case 73:
		break;
	case 74:
		break;
	case 75:
		break;
	case 76:
		break;
	case 77:
		break;
	case 78:
		break;
	case 79:
		break;
	case 80:
		break;
	case 81:
		break;
	case 82:
		break;
	case 83:
		break;
	case 84:
		break;
	case 85:
		break;
	case 86:
		break;
	case 87:
		break;
	case 88:
		break;
	case 89:
		break;
	case 90:
		break;
	case 91:
		break;
	case 92:
		break;
	case 93:
		break;
	case 94:
		break;
	case 95:
		break;
	case 96:
		break;
	case 97:
		break;
	case 98:
		break;
	case 99:
		break;

	}
	if(ret>=0) {
		data->my_calc->next_instr = (data->my_calc->next_instr + 1) % 100;
	}
	return ret;
}

int get_calc_cycles(tdata_t *data){
	return data->my_calc->num_of_cycles;
}

//*************** PRODUCER FUNCTIONS*************

int get_prod_tos(tdata_t *data) {
	int ret = semaphore_up(&data->my_prod->sm->tosMutex);
	return ret;


}
int get_prod_stack(tdata_t *data) {
	return semaphore_up(&data->my_prod->sm->stackMutex);
}
int get_prod_sm_value(tdata_t *data) {

	return semaphore_up(&data->my_prod->sm->calcMutex);
}

//functions to manipulate resources
int push_stack(tdata_t *data) {
	int temp = data->my_prod->sm->calcValue;
	int ret = pushStack(data->my_prod -> sm, temp);
	if(ret < 0) {
		semaphore_down(&data->my_prod->sm->tosMutex);
		semaphore_down(&data->my_prod->sm->stackMutex);
		semaphore_down(&data->my_prod->sm->calcMutex);
		data->my_prod->next_instr = 0;
	}
	return ret;
}

//functions to return resources
int return_prod_tos(tdata_t *data) {
	return semaphore_down(&data->my_prod->sm->tosMutex);
}
int return_prod_stack(tdata_t *data) {
	return semaphore_down(&data->my_prod->sm->stackMutex);
}
int return_prod_sm_value(tdata_t *data) {
	return semaphore_down(&data->my_prod->sm->calcMutex);
}

int next_pro_instr(tdata_t *data) {
	int ret = 0;
	switch (data->my_prod->next_instr) {
	case 0:
		ret = get_prod_tos(data);
		break;

	case 1:
		ret = get_prod_stack(data);
		break;
	case 2:
		ret = get_prod_sm_value(data);
		break;
	case 3:
		ret = push_stack(data);
		break;
	case 4:
		ret = return_prod_sm_value(data);
		break;
	case 5:
		ret = return_prod_stack(data);
		break;
	case 6:
		ret = return_prod_tos(data);
		data->my_prod->num_of_cycles++;
		break;
	case 7:
		break;
	case 8:
		break;
	case 9:
		break;
	case 10:
		break;
	case 11:
		break;
	case 12:
		break;
	case 13:
		break;
	case 14:
		break;
	case 15:
		break;
	case 16:
		break;
	case 17:
		break;
	case 18:
		break;
	case 19:
		break;
	case 20:
		break;
	case 21:
		break;
	case 22:
		break;
	case 23:
		break;
	case 24:
		break;
	case 25:
		break;
	case 26:
		break;
	case 27:
		break;
	case 28:
		break;
	case 29:
		break;
	case 30:
		break;
	case 31:
		break;
	case 32:
		break;
	case 33:
		break;
	case 34:
		break;
	case 35:
		break;
	case 36:
		break;
	case 37:
		break;
	case 38:
		break;
	case 39:
		break;
	case 40:
		break;
	case 41:
		break;
	case 42:
		break;
	case 43:
		break;
	case 44:
		break;
	case 45:
		break;
	case 46:
		break;
	case 47:
		break;
	case 48:
		break;
	case 49:
		break;
	case 50:
		break;
	case 51:
		break;
	case 52:
		break;
	case 53:
		break;
	case 54:
		break;
	case 55:
		break;
	case 56:
		break;
	case 57:
		break;
	case 58:
		break;
	case 59:
		break;
	case 60:
		break;
	case 61:
		break;
	case 62:
		break;
	case 63:
		break;
	case 64:
		break;
	case 65:
		break;
	case 66:
		break;
	case 67:
		break;
	case 68:
		break;
	case 69:
		break;
	case 70:
		break;
	case 71:
		break;
	case 72:
		break;
	case 73:
		break;
	case 74:
		break;
	case 75:
		break;
	case 76:
		break;
	case 77:
		break;
	case 78:
		break;
	case 79:
		break;
	case 80:
		break;
	case 81:
		break;
	case 82:
		break;
	case 83:
		break;
	case 84:
		break;
	case 85:
		break;
	case 86:
		break;
	case 87:
		break;
	case 88:
		break;
	case 89:
		break;
	case 90:
		break;
	case 91:
		break;
	case 92:
		break;
	case 93:
		break;
	case 94:
		break;
	case 95:
		break;
	case 96:
		break;
	case 97:
		break;
	case 98:
		break;
	case 99:
		break;

	}
	if(ret>=0) {
		data->my_prod->next_instr = (data->my_prod->next_instr + 1) % 100;
	}
	return ret;
}

int get_prod_cycles(tdata_t *data){
	return data->my_prod->num_of_cycles;
}

//*************** CONSUMER FUNCTIONS*************

//functions to acquire resources returns -1 if resource can't be acquired
//either because stack is full or resource has been locked by another process
int get_con_tos(tdata_t *data) {
	return semaphore_up(&data->my_cons -> sm->tosMutex);
}

int get_con_stack(tdata_t *data) {
	return semaphore_up(&data->my_cons-> sm->stackMutex);
}

int get_con_sm_value(tdata_t *data) {
	return semaphore_up(&data->my_cons->sm->calcMutex);
}

//functions to manipulate resources
int pop_stack(tdata_t *data) {
	int ret = popStack(data->my_cons -> sm);
	if(ret == -1) {
		semaphore_down(&data->my_cons -> sm->stackMutex);
		semaphore_down(&data->my_cons -> sm->tosMutex);
		data->my_cons->next_instr = 0;
	}
	return ret;
}

//functions to return resources

int return_con_sm_value(tdata_t *data) {
	return semaphore_down(&data->my_cons -> sm->calcMutex);

}

int return_con_stack(tdata_t *data) {
	return semaphore_down(&data->my_cons -> sm->stackMutex);
}

int return_con_tos(tdata_t *data) {
	return semaphore_down(&data->my_cons -> sm->tosMutex);
}

int next_con_instr(tdata_t *data) {
	int ret=0;
	switch (data->my_cons->next_instr) {
	case 0:
		ret = get_con_tos(data);
		break;

	case 1:
		ret = get_con_stack(data);
		break;
	case 2:
		ret = pop_stack(data);
		break;
	case 3:
		ret = return_con_stack(data);
		break;
	case 4:
		ret = return_con_tos(data);
		data->my_cons->num_of_cycles++;
		break;
	case 5:

	case 6:
		break;
	case 7:
		break;
	case 8:
		break;
	case 9:
		break;
	case 10:
		break;
	case 11:
		break;
	case 12:
		break;
	case 13:
		break;
	case 14:
		break;
	case 15:
		break;
	case 16:
		break;
	case 17:
		break;
	case 18:
		break;
	case 19:
		break;
	case 20:
		break;
	case 21:
		break;
	case 22:
		break;
	case 23:
		break;
	case 24:
		break;
	case 25:
		break;
	case 26:
		break;
	case 27:
		break;
	case 28:
		break;
	case 29:
		break;
	case 30:
		break;
	case 31:
		break;
	case 32:
		break;
	case 33:
		break;
	case 34:
		break;
	case 35:
		break;
	case 36:
		break;
	case 37:
		break;
	case 38:
		break;
	case 39:
		break;
	case 40:
		break;
	case 41:
		break;
	case 42:
		break;
	case 43:
		break;
	case 44:
		break;
	case 45:
		break;
	case 46:
		break;
	case 47:
		break;
	case 48:
		break;
	case 49:
		break;
	case 50:
		break;
	case 51:
		break;
	case 52:
		break;
	case 53:
		break;
	case 54:
		break;
	case 55:
		break;
	case 56:
		break;
	case 57:
		break;
	case 58:
		break;
	case 59:
		break;
	case 60:
		break;
	case 61:
		break;
	case 62:
		break;
	case 63:
		break;
	case 64:
		break;
	case 65:
		break;
	case 66:
		break;
	case 67:
		break;
	case 68:
		break;
	case 69:
		break;
	case 70:
		break;
	case 71:
		break;
	case 72:
		break;
	case 73:
		break;
	case 74:
		break;
	case 75:
		break;
	case 76:
		break;
	case 77:
		break;
	case 78:
		break;
	case 79:
		break;
	case 80:
		break;
	case 81:
		break;
	case 82:
		break;
	case 83:
		break;
	case 84:
		break;
	case 85:
		break;
	case 86:
		break;
	case 87:
		break;
	case 88:
		break;
	case 89:
		break;
	case 90:
		break;
	case 91:
		break;
	case 92:
		break;
	case 93:
		break;
	case 94:
		break;
	case 95:
		break;
	case 96:
		break;
	case 97:
		break;
	case 98:
		break;
	case 99:
		break;

	}
	if(ret>=0) {
		data->my_cons->next_instr = (data->my_cons->next_instr + 1) % 100;
	}
	return ret;
}
int get_con_cycles(tdata_t *data){
	return data->my_cons->num_of_cycles;
}

//*************** I/O FUNCTIONS*************

void set_io_1(tdata_t *data) {
	data->my_io = 1;
}

void set_io_0(tdata_t *data) {
	data->my_io = 0;
}

int print_message (tdata_t *data){
	int ret = -1;
	if(data->my_io == 1)
		data->my_io_counter = 0;

		switch (data->my_io_counter) {
		case 0:
			printf("Data has been received from user");
			set_io_0(data);
			ret = 0;
			break;
		case 1:
			printf("Waiting for user input");
			data->my_io_counter++;
			break;
		case 2:
			data->my_io_counter++;
			break;
		case 3:
			data->my_io_counter++;
			break;
		case 4:
			data->my_io_counter++;
			break;
		case 5:
			data->my_io_counter++;
			break;
		case 6:
			data->my_io_counter++;
			break;
		case 7:
			data->my_io_counter++;
			break;
		case 8:
			data->my_io_counter++;
			break;
		case 9:
			ret = data->my_io_counter++;
			break;
		case 10:
			data->my_io_counter = 1;
			break;
		}
	return ret;
}

